package com.study.server;

import com.study.server.codec.MessageDecoder;
import com.study.server.codec.MessageEncoder;
import com.study.server.message.GameMessage;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

import java.io.IOException;
import java.util.Random;

/**
 * Created by meen on 2017/12/4.
 */
public class TCPClient {

    private static Bootstrap boot = new Bootstrap();

    public TCPClient() {

    }

    public void start(String host, int port) {
        EventLoopGroup workGroup = new NioEventLoopGroup();
        try {
            boot.group(workGroup)
                    .channel(NioSocketChannel.class)
                    .option(ChannelOption.SO_KEEPALIVE, true)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            //这里我们先不写代码，这里主要是添加业务处理handler
                            ChannelPipeline pipeline = ch.pipeline();
                            pipeline.addLast("encoder", new MessageEncoder());
                            pipeline.addLast("handler", new ClientHandler());
                            pipeline.addLast("decoder", new MessageDecoder());
                        }
                    });
            ChannelFuture f = boot.connect(host, port).sync();
            if (f.isSuccess()) {
                System.out.println("Client starts success at " + host + ":" + port);
                new Thread(new SendTask(f.channel())).start();
            }
            f.channel().closeFuture().sync();//这里会导致线程阻塞
            //这里可以添加警报,表示服务器已down
        } catch (Exception e) {
//            e.printStackTrace();
            System.err.println("Client starts failed at " + host + ":" + port + " cause:" + e.getMessage());
        } finally {
            workGroup.shutdownGracefully();
        }
    }

    class ClientHandler extends SimpleChannelInboundHandler {

        @Override
        protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
            System.err.println("收到消息:" + msg);
            if (msg instanceof GameMessage) {
                GameMessage message = (GameMessage) msg;
                System.err.println("收到消息:" + message.getCmdId());
            }
        }

        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            System.err.println("client新开会话");


        }

        @Override
        public void channelInactive(ChannelHandlerContext ctx) throws Exception {
            System.err.println("会话关闭");

        }

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            System.err.println("会话异常");
            ctx.close();
            if (cause instanceof IOException) {
                return;
            }
            cause.printStackTrace();
        }
    }

    public static void main(String[] args) {
        String host = "127.0.0.1";
        int port = 18080;
        TCPClient client = new TCPClient();
        client.start(host, port);
    }


    class SendTask implements Runnable {

        private Channel channel;

        public SendTask(Channel channel) {
            this.channel = channel;
        }

        @Override
        public void run() {
            try {
                while (true) {
                    if(this.channel == null || !this.channel.isOpen()){
                        System.exit(0);
                    }
                    GameMessage gameMessage = new GameMessage(100);
                    gameMessage.putInt(123);
                    gameMessage.putString("hello,我是 "+new Random().nextInt(1000000));
                    this.channel.writeAndFlush(gameMessage);
                    System.err.println("发出消息:" + gameMessage.getCmdId());
                    Thread.sleep(1000);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}
